package Log;

use JIP::ToolSet; # load my commonly-used modules in a single import
use parent qw( Class::Base Class::Accessor::Fast );

use FileHandle;
use Time::localtime qw( localtime );
use English qw( -no_match_vars );
use Data::Dumper qw( Dumper );
use Carp qw( croak );

__PACKAGE__->mk_ro_accessors( qw(
    _outputFile
    _logLevel
    _outputHandle
    _outputBuffering
) );

my %availableMessages = (
    all   => [ qw( note debug warn error fatal dump ) ],
    info  => [ qw( note ) ],
    warn  => [ qw( warn ) ],
    error => [ qw( error fatal dump ) ],
    debug => [ qw( debug dump ) ],
);

sub init {
    my( $self, $config ) = @ARG;

    $self->{'_outputFile'} = $config->{'log_file'}
        or croak('required parameter "log_file" not defined');

    $self->{'_logLevel'} = $config->{'log_level'}
        or croak('required parameter "log_level" not defined');

    $self->{'_outputBuffering'} = $config->{'buffering'} || undef;

    $self->{'_outputHandle'} = FileHandle->new(
        $self->{'_outputFile'},
        O_WRONLY | O_CREAT | O_EXCL
    ) or croak( "couldn't open log file : ". $OS_ERROR );

    $self->{'_outputHandle'}->autoflush unless $self->{'_outputBuffering'};

    $self->{'_outputHandle'}->binmode(':utf8');

    return $self;
}

sub Note {
    my( $self, $userText ) = @ARG;

    $self->_writeMSG( message_type => 'INFO', message_text => $userText )
        if $self->_isAvailableMessage('note');
}

sub Debug {
    my( $self, $userText ) = @ARG;

    $self->_writeMSG( message_type => 'DEBUG', message_text => $userText )
        if $self->_isAvailableMessage('debug');
}

sub Warn {
    my( $self, $userText ) = @ARG;

    $self->_writeMSG( message_type => 'WARN', message_text => $userText )
        if $self->_isAvailableMessage('warn');
}

sub Error {
    my( $self, $userText ) = @ARG;

    $self->_writeMSG( message_type => 'ERROR', message_text => $userText )
        if $self->_isAvailableMessage('error');
}

sub Fatal {
    my( $self, $userText ) = @ARG;

    $self->_writeMSG( message_type => 'FATAL', message_text => $userText )
        if $self->_isAvailableMessage('fatal');
}

sub Dump {
    my( $self, $userText ) = @ARG;

    $self->_writeMSG( message_type => 'DUMP', message_text => Dumper( $userText ) )
        if $self->_isAvailableMessage('dump');
}

sub _isAvailableMessage {
    my( $self, $messageType ) = @ARG;

    return $messageType
        if $messageType ~~ @{ $availableMessages{ $self->_logLevel } };

    return;
}

sub _writeMSG {
    my $self = shift;

    my %args = @ARG;

    $self->_outputHandle->print(
        $self->_getLogMessage(
            message_type => $args{'message_type'},
            message_text => $args{'message_text'},
        )
    );
}

sub _getLogMessage {
    my $self = shift;

    my %args = @ARG;

    return $self->_getTimeStamp .' '.
           sprintf( "%-05s", $args{'message_type'} ) .' : '.
           $args{'message_text'} ."\n";
}

sub _getTimeStamp {
    my( $self, $tm ) = ( shift, localtime );

    return sprintf(
        "%04d-%02d-%02d %02d:%02d:%02d",
        $tm->year + 1900,
        $tm->mon + 1,
        $tm->mday,
        $tm->hour,
        $tm->min,
        $tm->sec
    );
}

1;
